package com.htfyun.ft.agingtest;

import android.bluetooth.BluetoothAdapter;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Color;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Message;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.style.ForegroundColorSpan;
import android.util.Log;
import android.util.Size;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;

import com.htfyun.ft.FTApplication;
import com.htfyun.ft.R;
import com.htfyun.ft.common.BatteryInfo;
import com.htfyun.ft.common.FTUtils;
import com.htfyun.ft.common.RecorderThread;
import com.htfyun.ft.config.FTProperty;
import com.htfyun.ft.utils.DebugLog;
import com.htfyun.ft.utils.FileReadWrite;
import com.htfyun.ft.utils.TimeStringUtils;
import com.htfyun.ft.view.CameraTextureView;
import com.htfyun.ft.wifilibrary.OnWifiStatusListener;
import com.htfyun.ft.wifilibrary.WiFiManager;
import com.htfyun.hardware.LedController;
import com.htfyun.serialport.ServoSingleton;
import com.htfyun.serialport.uartservo.OnServoListener;
import com.htfyun.serialport.uartservo.ServoControlAttr;
import com.htfyun.serialport.uartservo.ServoErrorAttr;
import com.htfyun.serialport.uartservo.ServoInterestedInfo;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

public class TestHardware extends AgingTestItemBase implements View.OnClickListener {


    @Override
    protected void doStartTest() {

        DebugLog.e("TestHardware doStartTest");

        addBtnLayout();

        startTestAll();
    }

    @Override
    protected void doStopTest() {
        DebugLog.e("TestHardware doStopTest");

        stopTestAll();

        removeBtnLayout();
        getAgingTestItemAttr().setKeepAging(false);
    }

    @Override
    public AgingTestItemAttr getAgingTestItemAttr() {
        return AgingTestItemAttr.hardware;
    }

    @Override
    public CharSequence getInfoString() {

        StringBuilder errorStringBuilder = new StringBuilder("");
        StringBuilder infoStringBuilder = new StringBuilder("");
        StringBuilder countStringBuilder = new StringBuilder("");

        //show log
        for (AgingHardwareItemAttr attr : AgingHardwareItemAttr.values()) {
            if (!TextUtils.isEmpty(attr.getErrorLog())) {
                errorStringBuilder.append(attr.getErrorLog());
                errorStringBuilder.append("\n");
            }
            if (!TextUtils.isEmpty(attr.getInfo())) {
                infoStringBuilder.append(attr.getInfo());
                infoStringBuilder.append("\n");
            }

            if (!TextUtils.isEmpty(attr.getItemCountString())) {
                countStringBuilder.append(attr.getItemCountString());
                countStringBuilder.append("\n");
            }

        }
        countStringBuilder.append(getString(R.string.aging_time, TimeStringUtils.makeTimeString(AgingLongSettingsAttr.aging_time_tick.get())));
        countStringBuilder.append("\n");

        if (!TextUtils.isEmpty(errorStringBuilder.toString())) {
            AgingBooleanSettingsAttr.hardware_fail.set(true);
        }

        SpannableString msp = new SpannableString(errorStringBuilder.toString()
                + infoStringBuilder.toString()
                + countStringBuilder.toString());
        ForegroundColorSpan colorSpan = new ForegroundColorSpan(Color.RED);
        msp.setSpan(colorSpan, 0, errorStringBuilder.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);

        return msp;
    }

    //////////////////
    // add btn
    /////////////////
    private Button btnMusicCtrl;
    private View btnContainer;

    private void addBtnLayout() {

        if (getRootView() == null) {
            return;
        }
        if (btnContainer != null) {
            removeBtnLayout();
        }
        btnContainer = LayoutInflater.from(getContext()).inflate(R.layout.aging_hardware_btn, null);
        getRootView().addView(btnContainer);

        btnMusicCtrl = (Button) btnContainer.findViewById(R.id.btnMusicCtrl);
        if (btnMusicCtrl != null) {
            btnMusicCtrl.setOnClickListener(this);
        }

        Button btnAgingKeep = (Button) btnContainer.findViewById(R.id.btnAgingKeep);
        if (btnAgingKeep != null) {
            btnAgingKeep.setOnClickListener(this);
            btnAgingKeep.setEnabled(!getAgingTestItemAttr().isKeepAging());
        }

    }

    private void removeBtnLayout() {
        if (getRootView() == null) {
            return;
        }
        if (btnContainer != null) {
            getRootView().removeView(btnContainer);
            btnContainer = null;
        }
    }

    /////////////////////////////////

    private void startTestAll() {
        if (AgingHardwareItemAttr.battery.isEnableTest()) batteryStart();
        if (AgingHardwareItemAttr.wifi.isEnableTest()) wifiStart();
        if (AgingHardwareItemAttr.bt.isEnableTest()) btStart();
        if (AgingHardwareItemAttr.speaker.isEnableTest()) {
            playSoundStart();
        } else {
            if (btnMusicCtrl != null) {
                btnMusicCtrl.setVisibility(View.INVISIBLE);
            }
        }

        if (AgingHardwareItemAttr.recorder.isEnableTest()) recordStart();
        if (AgingHardwareItemAttr.led.isEnableTest()) ledStart();
        if (AgingHardwareItemAttr.servo.isEnableTest()) servoStart();
        if (AgingHardwareItemAttr.light_sensor.isEnableTest()
                || AgingHardwareItemAttr.proximity_sensor.isEnableTest()) sensorStart();

        if (AgingHardwareItemAttr.camera.isEnableTest()) cameraStart();
        if (AgingHardwareItemAttr.emmc.isEnableTest()) emmcStart();
        if (AgingHardwareItemAttr.cpu.isEnableTest()) cpuStart();


    }

    private void stopTestAll() {

        if (AgingHardwareItemAttr.battery.isEnableTest()) batteryStop();
        if (AgingHardwareItemAttr.wifi.isEnableTest()) wifiStop();
        if (AgingHardwareItemAttr.bt.isEnableTest()) btStop();
        if (AgingHardwareItemAttr.speaker.isEnableTest()) playSoundStop();
        if (AgingHardwareItemAttr.recorder.isEnableTest()) recordStop();
        if (AgingHardwareItemAttr.led.isEnableTest()) ledStop();
        if (AgingHardwareItemAttr.servo.isEnableTest()) servoStop();
        if (AgingHardwareItemAttr.light_sensor.isEnableTest()
                || AgingHardwareItemAttr.proximity_sensor.isEnableTest()) sensorStop();

        if (AgingHardwareItemAttr.camera.isEnableTest()) cameraStop();
        if (AgingHardwareItemAttr.emmc.isEnableTest()) emmcStop();
        if (AgingHardwareItemAttr.cpu.isEnableTest()) cpuStop();

    }

    /////////////////////////////////
    // battery
    ////////////////////////////////
    private BatteryInfo batteryInfo;

    private void batteryStart() {

        if (batteryInfo == null) {
            batteryInfo = new BatteryInfo(getContext());
        }

        batteryInfo.startMonitor();
        batteryInfo.setOnBatteryChangedListener(onBatteryChangedListener);
    }

    private void batteryStop() {
        if (batteryInfo == null) {
            return;
        }
        batteryInfo.setOnBatteryChangedListener(null);
        batteryInfo.stopMonitor();
        batteryInfo = null;
    }

    private BatteryInfo.OnBatteryChangedListener onBatteryChangedListener =
            new BatteryInfo.OnBatteryChangedListener() {
                @Override
                public void onBatteryChangedListener(BatteryInfo info) {
                    String infoString = getString(R.string.info_battery,
                            info.getBatteryVoltage(),
                            info.getBatteryLevel(),
                            info.getBatteryStatusString());

                    AgingHardwareItemAttr.battery.setInfo(infoString);
                }
            };

    /////////////////////////////////
    // wifi
    /////////////////////////////////
    private WiFiManager mWiFiManager;

    private void wifiStart() {
        if (mWiFiManager == null) {
            mWiFiManager = WiFiManager.getInstance();
        }
        mWiFiManager.registerWifiReceiver();

        mWiFiManager.addOnWifiStatusListener(wifiEnabledListener);

        getHandler().sendEmptyMessage(MSG_TOGGLE_WIFI);

        setTxtWifiByWifiEnabled(mWiFiManager.isWifiEnabled());

    }

    private void wifiStop() {

        mWiFiManager.unregisterWifiReceiver();
        getHandler().removeMessages(MSG_TOGGLE_WIFI);

        mWiFiManager.closeWiFi();

    }

    private void wifiToggle() {

        if (!mWiFiManager.isWifiEnabled()) {

            mWiFiManager.openWiFi();

        } else {

            mWiFiManager.closeWiFi();

        }

    }

    private void setTxtWifiByWifiEnabled(boolean wifiEnabled) {
        int statusResId = R.string.wifi_status_off;
        if (wifiEnabled) {
            statusResId = R.string.wifi_status_on;
            AgingHardwareItemAttr.wifi.addOneTestCount();
        }

        AgingHardwareItemAttr.wifi.setInfo(getString(R.string.wifi_status, getString(statusResId)));

    }

    private OnWifiStatusListener wifiEnabledListener =
            new OnWifiStatusListener() {
                @Override
                public void onWifiEnabled(WifiStatusAttr status) {
                    switch (status) {
                        case enabling:
                            AgingHardwareItemAttr.wifi.setInfo(getString(R.string.wifi_status, getString(R.string.wifi_status_turning_on)));
                            break;
                        case enabled:
                            setTxtWifiByWifiEnabled(true);
                            break;
                        case disabling:
                            AgingHardwareItemAttr.wifi.setInfo(getString(R.string.wifi_status, getString(R.string.wifi_status_turning_off)));
                            break;
                        case disabled:
                            setTxtWifiByWifiEnabled(false);
                            break;
                        case unknown:
                            default:
                                AgingHardwareItemAttr.wifi.setInfo(getString(R.string.wifi_status, getString(R.string.wifi_status_unknown)));
                                break;
                    }
                }
            };

    ////////////////////////////
    // bt
    ///////////////////////////
    private BluetoothAdapter bluetoothAdapter;

    private void btStart() {

        if (bluetoothAdapter == null) {
            bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        }

        registerBT();

        getHandler().sendEmptyMessage(MSG_TOGGLE_BLUETOOTH);

        int statusResId = R.string.bt_status_off;
        if (bluetoothAdapter.isEnabled()) {
            statusResId = R.string.bt_status_on;
        }

        AgingHardwareItemAttr.bt.setInfo(getString(R.string.test_bt_status, getString(statusResId)));

    }

    private void btStop() {
        if (bluetoothAdapter == null) {
            return;
        }

        unregisterBT();

        getHandler().removeMessages(MSG_TOGGLE_BLUETOOTH);

        bluetoothAdapter.disable();

    }

    private void btToggle() {

        if (bluetoothAdapter == null) {
            return;
        }
        if (bluetoothAdapter.isEnabled()) {
            bluetoothAdapter.disable();
        } else {
            bluetoothAdapter.enable();
        }
    }

    private volatile boolean isBTRegistered = false;

    private synchronized void registerBT() {

        if (isBTRegistered) {
            return;
        }

        isBTRegistered = true;

        getContext().registerReceiver(BTReceiver, getIntentFilterOfBT());

    }

    private synchronized void unregisterBT() {

        if (!isBTRegistered) {
            return;
        }

        isBTRegistered = false;

        getContext().unregisterReceiver(BTReceiver);
    }

    private IntentFilter getIntentFilterOfBT() {
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
        return intentFilter;
    }

    private BroadcastReceiver BTReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            final String action = intent.getAction();
            if (action == null) {
                return;
            }

            if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {

                String stateExtra = BluetoothAdapter.EXTRA_STATE;
                int state = intent.getIntExtra(stateExtra, -1);
                int statusResId = R.string.bt_status_unknown;

                switch (state) {
                    case BluetoothAdapter.STATE_TURNING_ON:
                        statusResId = R.string.bt_status_turning_on;
                        break;
                    case BluetoothAdapter.STATE_ON:
                        statusResId = R.string.bt_status_on;
                        break;
                    case BluetoothAdapter.STATE_TURNING_OFF:
                        statusResId = R.string.bt_status_turning_off;
                        break;
                    case BluetoothAdapter.STATE_OFF:
                        statusResId = R.string.bt_status_off;
                        break;
                }


                if (state == BluetoothAdapter.STATE_ON) {
                    AgingHardwareItemAttr.bt.addOneTestCount();
                }

                AgingHardwareItemAttr.bt.setInfo(getString(R.string.test_bt_status, getString(statusResId)));

            }
        }
    };

    ////////////////////
    // play sound
    ////////////////////
    private MediaPlayer mediaPlayer;

    private void playSoundStart() {
        getHandler().sendEmptyMessage(MSG_PLAY_SOUND_START);

    }

    private void playSoundStop() {

        getHandler().removeMessages(MSG_PLAY_SOUND_START);

        if (mediaPlayer != null) {
            mediaPlayer.stop();
            mediaPlayer.release();//回收资源
            mediaPlayer = null;
        }

        updateBtnMusicCtrl();
    }

    private void doPlaySound() {
        if (mediaPlayer != null) {
            playSoundStop();
        }
        try {
            AudioManager am = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
            int maxVolume = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
            am.setStreamVolume(AudioManager.STREAM_MUSIC, maxVolume * 2 / 3, 0);

            mediaPlayer = MediaPlayer.create(getContext(), R.raw.music_qingzanggaoyuan);
//            mediaPlayer.setLooping(true);//这种这个后, setOnCompletionListener不能被调用了.
            mediaPlayer.start();

        } catch (Exception e) {
            DebugLog.e("exception e = " + e.getMessage());
        }

        mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {

            @Override
            public void onCompletion(MediaPlayer mp) {
                AgingHardwareItemAttr.speaker.addOneTestCount();

                getHandler().sendEmptyMessage(MSG_PLAY_SOUND_START);
            }
        });

        mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
            @Override
            public boolean onError(MediaPlayer mp, int what, int extra) {
                String error = "mediaPlayer onError, what = " + what + ", extra = " + extra;
                AgingHardwareItemAttr.speaker.setErrorLog(error);
                return true;
            }
        });

        updateBtnMusicCtrl();


    }

    private void updateBtnMusicCtrl() {
        if (btnMusicCtrl == null) {
            return;
        }

        int resId = R.string.aging_music_stop;
        if (mediaPlayer == null) {
            resId = R.string.aging_music_play;
        }

        btnMusicCtrl.setText(resId);

    }

    //////////////////////
    //    Recorder
    /////////////////////
    private RecorderThread recorderThread;
    private static final String RECORDER_FILE_PATH = FTUtils.getFTStorageDirectory() + File.separator + "aging_recorder.pcm";

    public void recordStart() {
        getHandler().removeMessages(MSG_RECORD_STOP);
        getHandler().sendEmptyMessage(MSG_RECORD_START);
    }

    private void recordStop() {
        stopRecordThread();

        getHandler().removeMessages(MSG_RECORD_STOP);
        getHandler().removeMessages(MSG_RECORD_START);
    }

    private void startRecordTread() {

        AgingHardwareItemAttr.recorder.addOneTestCount();
        getHandler().sendEmptyMessageDelayed(MSG_RECORD_STOP, PERIOD_RECORD_STOP);

        if (recorderThread != null) {
            stopRecordThread();
        }

        recorderThread = new RecorderThread("aging_rec-", null, RECORDER_FILE_PATH);
        recorderThread.start();

    }

    private void stopRecordThread() {

        getHandler().sendEmptyMessageDelayed(MSG_RECORD_START, PERIOD_RECORD_START);

        if (recorderThread != null) {
            recorderThread.joinThread();
            recorderThread = null;
        }
    }

    //////////////////////////////////
    // led_breath
    //////////////////////////////////
    private void ledStart() {
        getHandler().sendEmptyMessage(MSG_TOGGLE_LED);
    }

    private void ledStop() {
        getHandler().removeMessages(MSG_TOGGLE_LED);
        LedController.INSTANCE.setAllLedBrightness(0);
    }

    private void ledToggle() {
        AgingHardwareItemAttr.led.addOneTestCount();
        int count = AgingHardwareItemAttr.led.getTestCount();
        LedController.INSTANCE.setAllLedBrightness(count % 2 == 0 ? LedController.MAX_BRIGHTNESS : LedController.MIN_BRIGHTNESS);

    }

    //////////////////////////////////////////////
    // servo
    //////////////////////////////////////////////
    private final static int DefaultAngularVelocity = 50;
    private final static int DEFAULT_POSITION_DELTA = 5;//误差 5 度

    private OperationAttr currentOperationAttr = OperationAttr.right;
    private boolean servoDoRun = false;
    private boolean servoExist = false;

    private void servoStart() {

        servoStop();

        servoInit();

        getHandler().removeMessages(MSG_SERVO_OPERATION);
        getHandler().sendEmptyMessageDelayed(MSG_SERVO_OPERATION, DELAY_SERVO_OPERATION * 4);
        getHandler().sendEmptyMessageDelayed(MSG_SERVO_NOT_EXIST, DELAY_SERVO_NOT_EXIST);

    }

    private void servoStop() {

        getHandler().removeMessages(MSG_SERVO_OPERATION);
        getHandler().removeMessages(MSG_SERVO_DO_RUN);
        getHandler().removeMessages(MSG_SERVO_NOT_EXIST);

        servoDeInit();
        servoDeInit();

    }

    private void servoDeInit(){
        ServoSingleton.INSTANCE.getServoControl().unregisterServoListener(onServoListener);
        ServoSingleton.INSTANCE.getServoControl().servoStop();
    }

    private void servoInit() {
        ServoSingleton.INSTANCE.getServoControl().servoStop();
        ServoSingleton.INSTANCE.getServoControl().registerServoListener(onServoListener);

        servoInitSetAndGet();
        servoInitSetAndGet();

    }

    private void servoInitSetAndGet() {
        ServoSingleton.INSTANCE.getServoControl().setAngularVelocity(DefaultAngularVelocity);
        ServoSingleton.INSTANCE.getServoControl().setFeedbackTime_100ms(5);

        ServoSingleton.INSTANCE.getServoControl().getAngleAreaMax();
        ServoSingleton.INSTANCE.getServoControl().getAngleAreaMin();
        ServoSingleton.INSTANCE.getServoControl().getPosition();
        ServoSingleton.INSTANCE.getServoControl().getFeedbackTime_100ms();
        ServoSingleton.INSTANCE.getServoControl().getFirmwareVersion();
    }

    private boolean almostPosition(int srcPos, int desPos) {
        return (srcPos >= desPos - DEFAULT_POSITION_DELTA) && (srcPos <= desPos + DEFAULT_POSITION_DELTA);
    }

    private int getPositionMiddle(ServoInterestedInfo info) {
        int min = info.getAngleAreaMin();
        int max = info.getAngleAreaMax();
        return (min + max) / 2;
    }

    private void servoOperation() {

        switch (currentOperationAttr) {
            case right:
                ServoSingleton.INSTANCE.getServoControl().turnRight();
                break;
            case left:
                ServoSingleton.INSTANCE.getServoControl().turnLeft();
                break;
            case middle:
                int middle = getPositionMiddle(ServoSingleton.INSTANCE.getServoControl().getServoInterestedInfo());
                ServoSingleton.INSTANCE.getServoControl().setPosition(middle);
                break;
        }

        getHandler().sendEmptyMessageDelayed(MSG_SERVO_DO_RUN, DELAY_SERVO_DO_RUN);

    }

    private void servoSetDoRun() {
        servoDoRun = true;
        ServoSingleton.INSTANCE.getServoControl().getPosition();
    }

    private void servoNotExist() {
        AgingHardwareItemAttr.servo.setErrorLog(getString(R.string.servo_not_exist));
        servoStop();
    }

    private OperationAttr nextOperationAttr() {
        switch (currentOperationAttr) {
            case right:
                return OperationAttr.middle;
            case middle:
                return OperationAttr.left;
            case left:default: return OperationAttr.right;
        }
    }

    private void operationCheckAndNext(ServoInterestedInfo info) {

        if (!servoExist) {
            return;
        }
        if (!servoDoRun) {
            return;
        }

        if (info == null) {
            return;
        }

        if (info.isMoving()) {
            return;
        }

        servoDoRun = false;

        int desPos = info.getAngleAreaMax();

        switch (currentOperationAttr) {
            case right:
                desPos = info.getAngleAreaMax();
                break;
            case left:
                desPos = info.getAngleAreaMin();
                break;
            case middle:
                desPos = getPositionMiddle(info);
                break;
        }
        if (almostPosition(info.getPosition(), desPos)) {

            if (currentOperationAttr == OperationAttr.right) {
                AgingHardwareItemAttr.servo.addOneTestCount();
            }

            currentOperationAttr = nextOperationAttr();

        } else {

            String error = getString(R.string.servo_stop_wrong_position,
                    info.getPosition(), desPos, DEFAULT_POSITION_DELTA);

            AgingHardwareItemAttr.servo.setErrorLog(error);

            ServoSingleton.debugLog(error);

        }

        getHandler().removeMessages(MSG_SERVO_OPERATION);
        getHandler().sendEmptyMessageDelayed(MSG_SERVO_OPERATION, DELAY_SERVO_OPERATION);

    }

    private int prePosition = 0;
    private int samePositionCount = 0;
    private final int SAME_POSITION_COUNT_MAX = 5;
    private void updateServoInfo(ServoInterestedInfo info) {

        if (info == null) {
            return;
        }

        if (servoDoRun && prePosition == info.getPosition()) {
            samePositionCount++;
            if (samePositionCount >= SAME_POSITION_COUNT_MAX) {

                String error = getString(R.string.servo_same_position, prePosition, samePositionCount);
                AgingHardwareItemAttr.servo.setErrorLog(error);

            }
        } else {

            samePositionCount = 0;
        }

        prePosition = info.getPosition();

        String firmwareVersion = getString(R.string.servo_firmware_version, info.getFirmwareVersion());

        String angularVelocity = getString(R.string.status_current_angular_velocity, info.getAngularVelocity());

        String angle = getString(R.string.servo_show_info,
                info.getAngleAreaMin(),
                info.getAngleAreaMax());
        String feedbackTime = getString(R.string.status_feedback_time, info.getFeedbackTime_100ms());
        String position = getString(R.string.status_current_position, info.getPosition());
        String yes = getString(R.string.yes);
        String no = getString(R.string.no);
        String moveStatus = getString(R.string.status_moving, info.isMoving() ? yes : no);

        String curOp = "";
        if (currentOperationAttr != null) {
            curOp = getString(R.string.servo_operation, currentOperationAttr.getOperation());
        }

        StringBuilder sb = new StringBuilder();
        sb.append(firmwareVersion);
        sb.append(";");
        sb.append(angularVelocity);
        sb.append(";");
        sb.append(angle);
        sb.append(";");
        sb.append(feedbackTime);
        sb.append("\n");
        sb.append(curOp);
        sb.append(";");
        sb.append(position);
        sb.append(";");
        sb.append(moveStatus);
        sb.append(";");

        AgingHardwareItemAttr.servo.setInfo(sb.toString());

    }

    private OnServoListener onServoListener = new OnServoListener() {
        @Override
        public void onServoListener(List<ServoErrorAttr> errorAttrList, ServoControlAttr controlAttr, ServoControlAttr.Instruction instruction, ServoInterestedInfo info) {

            if (errorAttrList != null && !errorAttrList.isEmpty()) {
                StringBuilder errSB = new StringBuilder();
                for (ServoErrorAttr errorAttr : errorAttrList) {
                    errSB.append(errorAttr.toString());
                    errSB.append(";");
                }

                String error = getString(R.string.servo_error_happened, errSB.toString());
                AgingHardwareItemAttr.servo.setErrorLog(error);
                ServoSingleton.debugLog(error);

            }

            if (controlAttr == null) {
                return;
            }

            if (instruction == ServoControlAttr.Instruction.set) {
                return;
            }

            if (!servoExist) {
                servoExist = true;
                getHandler().removeMessages(MSG_SERVO_NOT_EXIST);
            }


            if (controlAttr == ServoControlAttr.position) {
                operationCheckAndNext(info);
            }

            updateServoInfo(info);

        }
    };

    private enum OperationAttr {
        right(R.string.servo_operation_right),//最大角度
        left(R.string.servo_operation_left),//最小角度
        middle(R.string.servo_operation_middle),
        ;

        private final int operationRes;
        private OperationAttr(int resId) {
            operationRes = resId;
        }

        public String getOperation() {
            if (operationRes  < 0) {
                return "";
            }
            try {
                final Context context = FTApplication.getContext();
                return context.getString(operationRes);
            } catch (Exception e) {

            }
            return "";
        }
    }

    ///////////////////////////////////
    // sensor
    //////////////////////////////////

    private SensorManager mSensorManager = null;
    private Sensor mSensorProximity = null;
    private Sensor mSensorLight = null;

    private void sensorStart() {
        mSensorManager = (SensorManager) getContext().getSystemService(Context.SENSOR_SERVICE);
        if (mSensorManager == null) {
            return;
        }
        mSensorProximity = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
        boolean result_ok = mSensorManager.registerListener(mSensorEventListener,
                mSensorProximity, SensorManager.SENSOR_DELAY_NORMAL);
        if (!result_ok) {
            AgingHardwareItemAttr.proximity_sensor.setErrorLog(getString(R.string.aging_proximity_sensor_failed));

        }

        mSensorLight = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
        result_ok = mSensorManager.registerListener(mSensorEventListener,
                mSensorLight, SensorManager.SENSOR_DELAY_NORMAL);
        if (!result_ok) {
            AgingHardwareItemAttr.light_sensor.setErrorLog(getString(R.string.aging_light_sensor_failed));
        }
    }

    private void sensorStop() {
        if (mSensorManager != null) {
            mSensorManager.unregisterListener(mSensorEventListener);
            mSensorProximity = null;
            mSensorLight = null;
            mSensorManager = null;
        }
    }

    private final SensorEventListener mSensorEventListener = new SensorEventListener() {

        @Override
        public void onAccuracyChanged(Sensor sensor, int accuracy) {
        }

        @Override
        public void onSensorChanged(SensorEvent sensorEvent) {
            // TODO Auto-generated method stub

            //图解中已经解释三个值的含义
            float X_lateral = sensorEvent.values[0];
//                float Y_longitudinal = sensorEvent.values[1];
//                float Z_vertical = sensorEvent.values[2];
            if (sensorEvent.sensor.getType() == Sensor.TYPE_LIGHT) {
                AgingHardwareItemAttr.light_sensor.setInfo(getString(R.string.aging_light_sensor_info, (int) X_lateral));

            } else if (sensorEvent.sensor.getType() == Sensor.TYPE_PROXIMITY) {
                AgingHardwareItemAttr.proximity_sensor.setInfo(getString(R.string.aging_proximity_sensor_info, (int) X_lateral));
            }
        }
    };

    ///////////////////////////////////////////
    // camera
    //////////////////////////////////////////
    private CameraTextureView mCameraTextureView;
    private final Object mCameraPreviewLock = new Object();
    private int mCameraPreviewFPSReal = 0;

    private void cameraStart() {

        try {

            if (getRootView() == null) {
                return;
            }
            synchronized (mCameraPreviewLock) {

                if (mCameraTextureView == null) {
                    mCameraTextureView = new CameraTextureView(getContext());
                    mCameraTextureView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
                    getRootView().addView(mCameraTextureView, 0);

                    mCameraTextureView.setCameraTextureCallback(new CameraTextureView.CameraTextureCallback() {
                        @Override
                        public void onCameraOpenOK() {

                        }

                        @Override
                        public void onCameraDisconnected() {

                        }

                        @Override
                        public void onCameraError() {

                            getHandler().sendEmptyMessage(MSG_CAMERA_NOT_FOUND);

                        }

                        @Override
                        public void onCameraPreview() {
                            mCameraPreviewFPSReal += 1;
                        }
                    });

                    getHandler().sendEmptyMessageDelayed(MSG_CALC_CAMERA_FSP, PERIOD_CALC_CAMERA_FSP);
                    mCameraPreviewFPSReal = 0;

                }

                mCameraTextureView.setKeepScreenOn(true);
            }
        } catch (Exception e) {

        }
    }


    private void cameraStop() {

        getHandler().removeMessages(MSG_CALC_CAMERA_FSP);

        if (mCameraTextureView != null && getRootView() != null) {

            synchronized (mCameraPreviewLock) {

                getRootView().removeView(mCameraTextureView);
                mCameraTextureView = null;
            }

        }

    }

    private void updateCameraPreviewInfo(int realFps) {

        synchronized (mCameraPreviewLock) {
            if (mCameraTextureView == null) {
                return;
            }
            Size previewSize = mCameraTextureView.getPreviewSize();
            if (previewSize == null) {
                return;
            }
            int maxFPS = mCameraTextureView.getMaxFPS();

            String info = getString(R.string.camera_front_info, previewSize.getWidth(), previewSize.getHeight(), maxFPS, realFps);
            AgingHardwareItemAttr.camera.setInfo(info);
        }

    }

    ///////////////////////////////////////////
    // emmc
    //////////////////////////////////////////

    private final static int MAX_COUNT_EMMC_TEST = 3;

    private List<TestEmmcController.EmmcInfo> emmcTestWriteList = new ArrayList<>();
    private List<TestEmmcController.EmmcInfo> emmcTestReadList = new ArrayList<>();

    public final static String PATH_TEST_EMMC_FAIL = FTUtils.getFTStorageDirectory() + File.separator + "testHW_emmcFail.log";

    private void emmcStart() {

        doEmmcStart();
    }

    private void emmcStop() {

        DebugLog.e("stop test emmc");

        doEmmcStop();
    }

    private void doEmmcStop() {

        TestEmmcController.getInstance().removeOnWROverListener(onWROverListener);
        TestEmmcController.getInstance().stopTest();

    }
    private void doEmmcStart() {

        int count = AgingHardwareItemAttr.emmc.getTestCount();

        if (count > MAX_COUNT_EMMC_TEST) {
            DebugLog.e("Test emmc count is " + count + ", No more emmc test");
            return;
        }

        for (TestEmmcController.EmmcInfo info : TestEmmcController.EmmcInfo.values()) {
            if (!emmcTestWriteList.contains(info)) {
                emmcTestWriteList.add(info);
            }
            if (!emmcTestReadList.contains(info)) {
                emmcTestReadList.add(info);
            }
        }

        DebugLog.e("Test emmc count is " + count + ", keep emmc test");

        TestEmmcController.getInstance().addOnWROverListener(onWROverListener);
        TestEmmcController.getInstance().setMarginSpace((count) * TestEmmcController._256_M);
        TestEmmcController.getInstance().setContext(getContext());
        TestEmmcController.getInstance().startTest();

    }


    private void checkTestEmmcAndTryStartAgain() {
        if (!(emmcTestReadList.isEmpty() && emmcTestWriteList.isEmpty())) {
            return;
        }

        // 完整的测了一次.
        AgingHardwareItemAttr.emmc.addOneTestCount();

        doEmmcStop();

        TestEmmcController.getInstance().deleteTestFiles();

        doEmmcStart();

    }
    private TestEmmcController.OnWROverListener onWROverListener =
            new TestEmmcController.OnWROverListener() {
                @Override
                public void onWriteOverListener(TestEmmcController.EmmcInfo info, long time_ms) {

                    emmcTestWriteList.remove(info);
                    checkTestEmmcAndTryStartAgain();
                }

                @Override
                public void onReadOverListener(TestEmmcController.EmmcInfo info, long time_ms) {

                    emmcTestReadList.remove(info);
                    checkTestEmmcAndTryStartAgain();

                }

                @Override
                public void onTestFailed(TestEmmcController.EmmcInfo info, String filePath, long offset, byte shouldValue, byte realValue) {

                    String log = "onTestFailed : info = " + info + ", filePath " + filePath
                            + ", offset = " + offset
                            + ", shouldValue =  0x" + Integer.toHexString((0xff & shouldValue))
                            + ", realValue = 0x" + Integer.toHexString((0xff & realValue))
                            + "\n";

                    DebugLog.e("EMMC error occurred, log path = " + PATH_TEST_EMMC_FAIL);

                    AgingBooleanSettingsAttr.emmc_fail.set(true);

                    FileReadWrite.writeAppendFile(PATH_TEST_EMMC_FAIL, log);

                    String error = getString(R.string.emmc_rw_error, PATH_TEST_EMMC_FAIL);
                    AgingHardwareItemAttr.emmc.setErrorLog(error);

                }
            };


    //////////////////////////////////////////////////////////////////////////
    // cpu test
    //////////////////////////////////////////////////////////////////////////

    private final static int MAX_COUNT_CPU_TEST = 3;

    private void cpuStart() {

        FTProperty.clearCpuTestResult();
        FTProperty.clearErrorBootCount();
        doStartCpuTest();
    }

    private void cpuStop() {
        getHandler().removeMessages(MSG_CHECK_TEST_CPU);
        FTProperty.startOrStopCpuTest(false);

    }

    private void doStartCpuTest() {
        FTProperty.startOrStopCpuTest(true);

        getHandler().removeMessages(MSG_CHECK_TEST_CPU);
        getHandler().sendEmptyMessageDelayed(MSG_CHECK_TEST_CPU, PERIOD_CHECK_TEST_CPU);

    }

    private void checkResultOfCpuTest() {

        FTProperty.CpuTestResultAttr attr = FTProperty.getCpuTestResultAttr();
        DebugLog.e("checkResultOfCpuTest attr = " + attr);

        switch (attr) {
            case ok:
            case fail:

                int count = AgingHardwareItemAttr.cpu.getTestCount();
                DebugLog.e("songshitian checkResultOfCpuTest ok, count = " + count);
                if (count >= MAX_COUNT_CPU_TEST) {
                    break;
                }
                AgingHardwareItemAttr.cpu.addOneTestCount();

                if (attr == FTProperty.CpuTestResultAttr.fail) {
                    AgingBooleanSettingsAttr.cpu_fail.set(true);

                    String error = getString(R.string.cpu_test_error);
                    AgingHardwareItemAttr.cpu.setErrorLog(error);

                }

                doStartCpuTest();

                break;
            default:
                getHandler().sendEmptyMessageDelayed(MSG_CHECK_TEST_CPU, PERIOD_CHECK_TEST_CPU);
                break;
        }
    }



    ////////////////////////////////////////////////////
    ////////////////////////////////////////////////////
    private static final int MSG_CALC_CAMERA_FSP = 100;
    private static final int PERIOD_CALC_CAMERA_FSP = 1000;
    private static final int MSG_CAMERA_NOT_FOUND = 101;

    private static final int MSG_TOGGLE_WIFI = 200;
    private static final int PERIOD_TOGGLE_WIFI = 30 * 1000;

    private static final int MSG_TOGGLE_BLUETOOTH = 300;
    private static final int PERIOD_TOGGLE_BLUETOOTH = 30 * 1000;

    private final static int MSG_TOGGLE_LED = 400;
    private final static int PERIOD_TOGGLE_LED = 5000;

    private static final int MSG_SERVO_OPERATION = 500;
    private final static int DELAY_SERVO_OPERATION = 300;
    private static final int MSG_SERVO_DO_RUN = 501;
    private static final int DELAY_SERVO_DO_RUN = 500;
    private static final int MSG_SERVO_NOT_EXIST = 502;
    private static final int DELAY_SERVO_NOT_EXIST = 3000;


    private static final int MSG_RECORD_START = 600;
    private static final int PERIOD_RECORD_START = 20 * 1000;

    private static final int MSG_RECORD_STOP = 700;
    private static final int PERIOD_RECORD_STOP = 20 * 1000;

    private static final int MSG_PLAY_SOUND_START = 800;

    private static final int MSG_CHECK_TEST_CPU = 900;
    private static final int PERIOD_CHECK_TEST_CPU = 1000 * 60 * 4;// 4min


    @Override
    public void handleMessage(Message msg) {

        final int what = msg.what;

        switch (what) {

            case MSG_CAMERA_NOT_FOUND:
                AgingHardwareItemAttr.camera.setErrorLog(getString(R.string.camera_not_found));
                break;
            case MSG_CALC_CAMERA_FSP: {
                int curFPS = mCameraPreviewFPSReal;
                updateCameraPreviewInfo(curFPS);
                getHandler().sendEmptyMessageDelayed(msg.what, PERIOD_CALC_CAMERA_FSP);
                mCameraPreviewFPSReal = 0;
                break;
            }
            case MSG_TOGGLE_WIFI:
                wifiToggle();
                getHandler().sendEmptyMessageDelayed(msg.what, PERIOD_TOGGLE_WIFI);
                break;
            case MSG_TOGGLE_BLUETOOTH:
                btToggle();
                getHandler().sendEmptyMessageDelayed(msg.what, PERIOD_TOGGLE_BLUETOOTH);
                break;
            case MSG_TOGGLE_LED:
                ledToggle();
                getHandler().sendEmptyMessageDelayed(msg.what, PERIOD_TOGGLE_LED);
                break;
            case MSG_SERVO_OPERATION:
                servoOperation();
                break;
            case MSG_SERVO_DO_RUN:
                servoSetDoRun();
                break;
            case MSG_SERVO_NOT_EXIST:
                servoNotExist();
                break;
            case MSG_PLAY_SOUND_START:
                doPlaySound();
                break;
            case MSG_RECORD_START:
                startRecordTread();
                break;
            case MSG_RECORD_STOP:
                stopRecordThread();
                break;
            case MSG_CHECK_TEST_CPU:
                checkResultOfCpuTest();
                break;
            default:
                break;

        }

    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {

            case R.id.btnMusicCtrl:
                if (mediaPlayer == null) {
                    playSoundStart();
                } else {
                    playSoundStop();
                }
                break;
            case R.id.btnAgingKeep:
                getAgingTestItemAttr().setKeepAging(true);
                v.setEnabled(false);
                break;
        }
    }
}
